;; The first four lines of this file were added by Dracula.
;; They tell DrScheme that this is a Dracula Modular ACL2 program.
;; Leave these lines unchanged so that DrScheme can properly load this file.
#reader(planet "reader.rkt" ("cce" "dracula.plt") "modular" "lang")
(require "irotate.lisp")
(require "mbmptree.lisp")
(require "mdatagenerators.lisp")

; The Rotate module, responsible for rotating bitmaps either
; 90 degrees, 180 degrees or 270 degrees.
(module MRotate
  (import Ibmptree)
  (import IDataGenerators)
  
  ; Rotates a given image 90 degrees, pixel-by-pixel. Implements
  ; the following C++ algorithm:
  ;
  ; for (int x = 0; x < SrcBitmap->Width; x++) {
  ;   for(int y = 0; y < SrcBitmap->Height; y++) {
  ;      DestBitmap[y][SrcBitmap->Width - 1 - x] = 
  ;          SrcBitmap[x][y]; }}
  ;
  ; pre: oldtr - the source image
  ;      oldwidth - the width of the image before the rotation
  ;      newtr - the tree that's being built into the new image
  ;      xcurr - the current x index in the outer for-loop
  ;      xmax - the maximum value for x in the outer for-loop
  ;      ycurr - the current y index in the outer for-loop
  ;      ymax - the maximum value for y in the outer for-loop
  ;      currrow - the row that's currently being processed in the source
  ; post: a new bitmap tree, rotated 90 degrees from the original
  (defun rotate-90-helper (oldtr oldwidth newtr xcurr xmax ycurr ymax currrow)
      ; is the current x index less than its max?
      (if (< xcurr xmax)
          ; yes, is the current y index less than its max?
          (if (< ycurr ymax)
              ; yes, so dest[y][oldwidth - 1 - x] = src[x][y]
              (rotate-90-helper oldtr oldwidth (insert-pixel newtr (list ycurr (- (- oldwidth 1) xcurr) 
                   (cdr (car currrow)))) xcurr xmax (+ ycurr 1) ymax (cdr currrow))
              ; no, so reset y to 0 and increment x
              (rotate-90-helper oldtr oldwidth newtr (+ xcurr 1) xmax 0 ymax (get-row oldtr (+ xcurr 1))))
          ; x has extended past its max, so the recursion is done - return the new tree
          newtr))
  
  
  ; Rotates the given picture 90 degrees using its helper
  ; function
  ; pre: tree - the bitmap tree
  ; post: a new bmp-tree that's the original one
  ; rotated 90 degrees
  (defun rotate-90 (tree)
    (let* ((oldheader (get-header tree))
           (oldheight (car (get-dimensions tree)))
           (oldwidth (cdr (get-dimensions tree)))
           (newwidth oldheight)
           (newheight oldwidth)
           (tmptree (insert-header (empty-bmp-tree) oldheader))
           (newtree (set-dimensions-header tmptree newheight newwidth)))
      (rotate-90-helper tree oldheight newtree 0 oldheight 0 oldwidth (get-row tree 0))))
  
  ; Rotates a given image 180 degrees, pixel-by-pixel. Implements
  ; the following C++ algorithm:
  ;
  ; for (int x = 0; x < SrcBitmap->Height; x++) { 
  ;    for(int y = 0; y < SrcBitmap->Width; y++) { 
  ;       DestBitmap->Canvas->Pixels[y][SrcBitmap->Height - 1 - x] = 
  ;            SrcBitmap->Canvas->Pixels[x][y]; }} 
  ;
  ; pre: oldtr - the source image
  ;      height - the height of the image
  ;      newtr - the tree that's being built into the new image
  ;      xcurr - the current x index in the outer for-loop
  ;      xmax - the maximum value for x in the outer for-loop
  ;      ycurr - the current y index in the outer for-loop
  ;      ymax - the maximum value for y in the outer for-loop
  ;      currrow - the row that's being processed in the source image
  ; post: a new bitmap tree, rotated 180 degrees from the original
  (defun rotate-180-helper (oldtr height newtr xcurr xmax ycurr ymax currrow)
    ; is the current x index less than its max?
    (if (< xcurr xmax)
        ; yes, is the current y index less than its max?
        (if (< ycurr ymax)
            ; yes, so dest[x][oldheight - 1 - y] = src[x][y]
            (rotate-180-helper oldtr height (insert-pixel newtr (list xcurr (- (- height 1) ycurr) 
                 (cdr (car currrow)))) xcurr xmax (+ ycurr 1) ymax (cdr currrow))
            ; no, so reset y to 0 and increment x
            (rotate-180-helper oldtr height newtr (+ xcurr 1) xmax 0 ymax (get-row oldtr (+ xcurr 1))))
        ; x has extended past its max, so the recursion is done - return the new tree
        newtr))
       
  
  ; Rotates the given picture 180 degrees using its helper
  ; function
  ; pre: tree - the bitmap tree
  ; post: a new bmp-tree that's the original one
  ; rotated 180 degrees
  (defun rotate-180 (tree)
    (let* ((oldheader (get-header tree))
           (oldheight (car (get-dimensions tree)))
           (oldwidth (cdr (get-dimensions tree)))
           (newwidth oldwidth)
           (newheight oldheight)
           (tmptree (insert-header (empty-bmp-tree) oldheader))
           (newtree (set-dimensions-header tmptree newheight newwidth)))
      (rotate-90 (rotate-90 tree))))
      ;(rotate-180-helper tree oldheight newtree 0 oldwidth 0 oldheight (get-row tree 0))))
  
  ; Rotates a given image 270 degrees, pixel-by-pixel. Implements
  ; the following C++ algorithm:
  ;
  ; for (int x = 0; x < SrcBitmap->Height; x++) {
  ;   for(int y = 0; y < SrcBitmap->Width; y++) {
  ;      DestBitmap[y][x] = SrcBitmap[x][y]; }}
  ;
  ; pre: oldtr - the source image
  ;      newwidth - the width of the new image
  ;      newtr - the tree that's being built into the new image
  ;      xcurr - the current x index in the outer for-loop
  ;      xmax - the maximum value for x in the outer for-loop
  ;      ycurr - the current y index in the outer for-loop
  ;      ymax - the maximum value for y in the outer for-loop
  ;      currrow - the row that's currently being processed
  ; post: a new bitmap tree, rotated 90 degrees from the original
  (defun rotate-270-helper (oldtr newtr xcurr xmax ycurr ymax currrow)
      ; is the current x index less than its max?
      (if (< xcurr xmax)
          ; yes, is the current y index less than its max?
          (if (< ycurr ymax)
              ; yes, so dest[y][x] = src[x][y]
              (rotate-270-helper oldtr (insert-pixel newtr (list ycurr xcurr 
                   (cdr (car currrow)))) xcurr xmax (+ ycurr 1) ymax (cdr currrow))
              ; no, so reset y to 0 and increment x
              (rotate-270-helper oldtr newtr (+ xcurr 1) xmax 0 ymax (get-row oldtr (+ xcurr 1))))
          ; x has extended past its max, so the recursion is done - return the new tree
          newtr))
  
  
  ; Rotates the given picture 270 degrees using its helper
  ; function
  ; pre: tree - the bitmap tree
  ; post: a new bmp-tree that's the original one
  ; rotated 270 degrees
  (defun rotate-270 (tree)
    (let* ((oldheader (get-header tree))
           (oldheight (car (get-dimensions tree)))
           (oldwidth (cdr (get-dimensions tree)))
           (newwidth oldheight)
           (newheight oldwidth)
           (tmptree (insert-header (empty-bmp-tree) oldheader))
           (newtree (set-dimensions-header tmptree newheight newwidth)))
      (rotate-90 (rotate-90 (rotate-90 tree)))))
      ;(rotate-270-helper tree newtree 0 oldheight 0 oldwidth (get-row tree 0))))
 
  ; Rotates the image either 90, 180, or 270 degrees as specified
  ; by the angle parameter. Uses rotate-90, rotate-180 and rotate-270.
  ; pre: tr - a bmp-tree
  ;      angle - an integer in { 90, 180, 270 }
  ; post: a bmp-tree representation of the rotated image
  (defun rotate (tree angle)
    ; Is tr a nonempty bmp-tree?
    ; And is orientation a valid number?
    (if (and (bmp-tree? tree) (consp tree) (consp (get-header tree))
             (or (= angle 90) (= angle 180) (= angle 270)))
        ; yes, call the appropriate function
        (cond
          ((= angle 90) (rotate-90 tree))
          ((= angle 180) (rotate-180 tree))
          ((= angle 270) (rotate-270 tree)))
        ; no, return the unchanged tree
        tree))
  
  (export IRotate))